import pandas as pd
import numpy as np
import logging
from sklearn.preprocessing import MinMaxScaler

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class DividendDataProcessor:
    """
    分红数据预处理类
    用于处理新浪财经历史分红数据
    """
    
    def __init__(self):
        """
        初始化数据处理器
        """
        self.df = None
    
    def load_data(self, file_path="新浪财经历史分红数据.xlsx"):
        """
        加载Excel数据
        
        Args:
            file_path: 数据文件路径
            
        Returns:
            bool: 是否成功加载
        """
        try:
            self.df = pd.read_excel(file_path)
            logger.info(f"成功加载数据，数据形状: {self.df.shape}")
            return True
        except Exception as e:
            logger.error(f"加载数据时出错: {str(e)}")
            return False
    
    def check_data_shape(self):
        """
        检查数据形状
        """
        if self.df is None:
            logger.warning("请先加载数据")
            return
        
        logger.info(f"数据形状: {self.df.shape}")
        logger.info(f"数据列: {list(self.df.columns)}")
        logger.info(f"数据类型:\n{self.df.dtypes}")
    
    def check_duplicates(self):
        """
        检查重复值
        """
        if self.df is None:
            logger.warning("请先加载数据")
            return
        
        # 检查整体重复行
        total_duplicates = self.df.duplicated().sum()
        logger.info(f"整体重复行数量: {total_duplicates}")
        
        # 检查特定列的重复值
        columns_to_check = ['代码', '名称', '详细']
        
        for col in columns_to_check:
            if col in self.df.columns:
                unique_count = self.df[col].nunique()
                total_count = len(self.df)
                duplicate_count = total_count - unique_count
                logger.info(f"列 '{col}' 的重复值数量: {duplicate_count}")
                logger.info(f"列 '{col}' 的唯一值数量: {unique_count}")
                logger.info(f"列 '{col}' 的唯一值比例: {unique_count/total_count:.2%}")
            else:
                logger.warning(f"列 '{col}' 不存在于数据中")
    
    def show_head(self, n=5):
        """
        展示数据前n行
        
        Args:
            n: 显示的行数
        """
        if self.df is None:
            logger.warning("请先加载数据")
            return
        
        logger.info(f"数据前 {n} 行:")
        print(self.df.head(n))
    
    def adjust_data(self):
        """
        调整数据，处理常见问题
        """
        if self.df is None:
            logger.warning("请先加载数据")
            return
        
        # 去除空白字符
        for col in self.df.select_dtypes(include=['object']).columns:
            self.df[col] = self.df[col].str.strip()
        
        # 处理缺失值
        logger.info(f"缺失值情况:\n{self.df.isnull().sum()}")
        
        # 可以根据需要添加更多的数据调整逻辑
    
    def process_listing_date(self):
        """
        处理上市日期，提取年、月、日
        """
        if self.df is None:
            logger.warning("请先加载数据")
            return
        
        date_column = '上市日期'  # 假设列名为'上市日期'
        
        if date_column not in self.df.columns:
            # 尝试查找可能的日期列
            date_columns = [col for col in self.df.columns if '日期' in col]
            if date_columns:
                date_column = date_columns[0]
                logger.info(f"使用列 '{date_column}' 作为日期列")
            else:
                logger.warning("未找到包含'日期'的列")
                return
        
        try:
            # 转换为日期类型
            self.df[date_column] = pd.to_datetime(self.df[date_column], errors='coerce')
            
            # 提取年、月、日
            self.df['上市年份'] = self.df[date_column].dt.year
            self.df['上市月份'] = self.df[date_column].dt.month
            self.df['上市日'] = self.df[date_column].dt.day
            
            logger.info(f"已从 {date_column} 提取年、月、日信息")
            
        except Exception as e:
            logger.error(f"处理上市日期时出错: {str(e)}")
    
    def normalize_numeric_variables(self):
        """
        对数值型变量进行归一化处理
        """
        if self.df is None:
            logger.warning("请先加载数据")
            return
        
        try:
            # 定义需要归一化的列
            numeric_columns = ['累计股息(%)', '年均股息(%)', '分红次数', '融资总额(亿元)']
            
            # 创建归一化器
            scaler = MinMaxScaler()
            
            # 检查并转换数据类型
            normalized_columns = []
            
            for col in numeric_columns:
                if col in self.df.columns:
                    try:
                        # 保存原始值
                        original_col = f"{col}_原始"
                        self.df[original_col] = self.df[col].copy()
                        
                        # 清理和转换数据
                        if self.df[col].dtype == 'object':
                            # 清理字符串，移除百分号、单位、逗号等
                            self.df[col] = self.df[col].astype(str).str.replace('%', '').str.replace('％', '')
                            self.df[col] = self.df[col].str.replace('亿元', '').str.replace(',', '').str.strip()
                            
                            # 替换空字符串为NaN
                            self.df[col] = self.df[col].replace('', np.nan)
                        
                        # 转换为数值类型
                        self.df[col] = pd.to_numeric(self.df[col], errors='coerce')
                        
                        # 处理缺失值
                        missing_count = self.df[col].isnull().sum()
                        if missing_count > 0:
                            logger.info(f"列 '{col}' 中有 {missing_count} 个缺失值，将用0填充")
                            self.df[col].fillna(0, inplace=True)
                        
                        logger.info(f"已成功转换列 '{col}' 为数值类型")
                        normalized_columns.append(col)
                        
                    except Exception as e:
                        logger.warning(f"转换列 '{col}' 为数值类型时出错: {str(e)}")
            
            # 对数值列进行归一化
            for col in normalized_columns:
                try:
                    # 检查是否有足够的有效数据进行归一化
                    if self.df[col].std() > 0:  # 确保标准差大于0，即数据有变化
                        # 进行归一化
                        normalized_values = scaler.fit_transform(self.df[[col]])
                        self.df[f"{col}_归一化"] = normalized_values
                        logger.info(f"已对列 '{col}' 进行归一化处理")
                    else:
                        logger.info(f"列 '{col}' 的数据无变化，跳过归一化")
                        self.df[f"{col}_归一化"] = 0.5  # 统一赋值为0.5
                except Exception as e:
                    logger.error(f"归一化列 '{col}' 时出错: {str(e)}")
            
            if normalized_columns:
                logger.info(f"成功处理了以下数值列: {', '.join(normalized_columns)}")
            else:
                logger.warning("未找到需要归一化的数值列")
                
        except Exception as e:
            logger.error(f"归一化数值变量时出错: {str(e)}")
    
    def save_processed_data(self, file_path="新浪财经历史分红数据_预处理.xlsx"):
        """
        保存预处理后的数据
        
        Args:
            file_path: 保存路径
            
        Returns:
            bool: 是否成功保存
        """
        if self.df is None:
            logger.warning("请先加载数据")
            return False
        
        try:
            self.df.to_excel(file_path, index=False, engine='openpyxl')
            logger.info(f"预处理后的数据已成功保存到 {file_path}")
            return True
        except Exception as e:
            logger.error(f"保存预处理数据时出错: {str(e)}")
            return False
    
    def process_all(self, input_file="新浪财经历史分红数据.xlsx", output_file="新浪财经历史分红数据_预处理.xlsx"):
        """
        执行完整的预处理流程
        
        Args:
            input_file: 输入文件路径
            output_file: 输出文件路径
        """
        # 1. 加载数据
        if not self.load_data(input_file):
            return False
        
        # 2. 检查数据形状
        self.check_data_shape()
        
        # 3. 检查重复值
        self.check_duplicates()
        
        # 4. 展示前5行
        self.show_head(5)
        
        # 5. 调整数据
        self.adjust_data()
        
        # 6. 处理上市日期
        self.process_listing_date()
        
        # 7. 归一化数值变量
        self.normalize_numeric_variables()
        
        # 8. 保存处理后的数据
        return self.save_processed_data(output_file)

def main():
    """
    主函数，执行数据预处理流程
    """
    # 创建数据处理器实例
    processor = DividendDataProcessor()
    
    try:
        # 执行完整的预处理流程
        success = processor.process_all()
        
        if success:
            logger.info("数据预处理完成！")
        else:
            logger.error("数据预处理失败！")
            
    except Exception as e:
        logger.error(f"预处理过程中发生错误: {str(e)}")

if __name__ == "__main__":
    main()